package com.yang.core.plugins.validation;

import com.yang.core.api.RestClientBuilder;
import com.yang.core.api.RestClientInterceptor;
import com.yang.core.model.RequestContext;
import com.yang.core.model.ResponseContext;
import com.yang.core.model.ExceptionContext;
import com.yang.core.extension.ExtensionPoint;
import com.yang.core.extension.RestClientExtension;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 内容验证扩展
 * 用于验证请求和响应内容中是否包含指定的内容
 */
@Slf4j
@ExtensionPoint(
    name = "contentValidation",
    description = "内容验证扩展，检查请求和响应中是否包含指定内容",
    category = ExtensionPoint.Category.VALIDATION,
    order = 50
)
public class ContentValidationExtension implements RestClientExtension {

    private final ContentValidationConfig config;

    public ContentValidationExtension() {
        this.config = new ContentValidationConfig();
    }

    public ContentValidationExtension(ContentValidationConfig config) {
        this.config = config;
    }

    @Override
    public void extend(RestClientBuilder builder) {
        if (config == null || !config.isEnabled()) {
            return;
        }

        builder.addInterceptor(new ContentValidationInterceptor(config));
        log.info("启用内容验证扩展，检查规则数: {}", config.getValidationRules().size());
    }

    /**
     * 内容验证配置
     */
    public static class ContentValidationConfig {
        private boolean enabled = true;
        private List<ValidationRule> validationRules;
        private boolean failOnViolation = true;
        private boolean logViolations = true;

        public ContentValidationConfig() {
            this.validationRules = new ArrayList<>();
        }

        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        public List<ValidationRule> getValidationRules() { return validationRules; }
        public void setValidationRules(List<ValidationRule> validationRules) { this.validationRules = validationRules; }
        public boolean isFailOnViolation() { return failOnViolation; }
        public void setFailOnViolation(boolean failOnViolation) { this.failOnViolation = failOnViolation; }
        public boolean isLogViolations() { return logViolations; }
        public void setLogViolations(boolean logViolations) { this.logViolations = logViolations; }

        /**
         * 添加验证规则
         */
        public ContentValidationConfig addRule(ValidationRule rule) {
            this.validationRules.add(rule);
            return this;
        }

        /**
         * 添加字符串包含验证规则
         */
        public ContentValidationConfig addContainsRule(String target, String searchText, ValidationType type) {
            return addRule(new StringContainsRule(target, searchText, type, true, logViolations));
        }

        /**
         * 添加正则表达式验证规则
         */
        public ContentValidationConfig addRegexRule(String target, String pattern, ValidationType type) {
            return addRule(new RegexRule(target, pattern, type, logViolations));
        }
    }

    /**
     * 验证规则接口
     */
    public interface ValidationRule {
        boolean validate(RequestContext requestContext, ResponseContext responseContext);
        String getDescription();
        String getTarget();
        ValidationType getType();
    }

    /**
     * 验证类型
     */
    public enum ValidationType {
        REQUEST_HEADER,    // 请求头
        REQUEST_BODY,      // 请求体
        REQUEST_URL,       // 请求URL
        RESPONSE_HEADER,   // 响应头
        RESPONSE_BODY,     // 响应体
        RESPONSE_STATUS    // 响应状态码
    }

    /**
     * 字符串包含验证规则
     */
    public static class StringContainsRule implements ValidationRule {
        private final String target;
        private final String searchText;
        private final ValidationType type;
        private final boolean caseSensitive;
        private final boolean logViolations;

        public StringContainsRule(String target, String searchText, ValidationType type) {
            this(target, searchText, type, true);
        }

        public StringContainsRule(String target, String searchText, ValidationType type, boolean caseSensitive) {
            this(target, searchText, type, caseSensitive, true);
        }

        public StringContainsRule(String target, String searchText, ValidationType type, boolean caseSensitive, boolean logViolations) {
            this.target = target;
            this.searchText = searchText;
            this.type = type;
            this.caseSensitive = caseSensitive;
            this.logViolations = logViolations;
        }

        @Override
        public boolean validate(RequestContext requestContext, ResponseContext responseContext) {
            String content = getContent(requestContext, responseContext);
            if (content == null) {
                return true; // 如果没有内容，则通过验证
            }

            String searchContent = caseSensitive ? content : content.toLowerCase();
            String searchPattern = caseSensitive ? searchText : searchText.toLowerCase();

            boolean contains = searchContent.contains(searchPattern);

            if (!contains && logViolations) {
                log.warn("内容验证失败: {} 中未找到 '{}'", getTargetDescription(), searchText);
            }

            return contains;
        }

        private String getContent(RequestContext requestContext, ResponseContext responseContext) {
            return switch (type) {
                case REQUEST_HEADER -> getHeaderValue(requestContext);
                case REQUEST_BODY -> getBodyValue(requestContext);
                case REQUEST_URL -> requestContext.getUrl();
                case RESPONSE_HEADER -> getHeaderValue(responseContext);
                case RESPONSE_BODY -> getBodyValue(responseContext);
                case RESPONSE_STATUS -> String.valueOf(responseContext.getStatusCode());
            };
        }

        private String getHeaderValue(RequestContext context) {
            Map<String, String> headers = context.getHeaders();
            return headers != null ? headers.get(target) : null;
        }

        private String getHeaderValue(ResponseContext context) {
            Map<String, String> headers = context.getHeaders();
            return headers != null ? headers.get(target) : null;
        }

        private String getBodyValue(RequestContext context) {
            Object body = context.getBody();
            return body != null ? body.toString() : null;
        }

        private String getBodyValue(ResponseContext context) {
            String body = context.getBody();
            return body != null ? body : null;
        }

        @Override
        public String getDescription() {
            return String.format("检查%s中是否包含'%s'", getTargetDescription(), searchText);
        }

        private String getTargetDescription() {
            return switch (type) {
                case REQUEST_HEADER -> "请求头'" + target + "'";
                case REQUEST_BODY -> "请求体";
                case REQUEST_URL -> "请求URL";
                case RESPONSE_HEADER -> "响应头'" + target + "'";
                case RESPONSE_BODY -> "响应体";
                case RESPONSE_STATUS -> "响应状态码";
            };
        }

        @Override
        public String getTarget() { return target; }

        @Override
        public ValidationType getType() { return type; }
    }

    /**
     * 正则表达式验证规则
     */
    public static class RegexRule implements ValidationRule {
        private final String target;
        private final Pattern pattern;
        private final ValidationType type;
        private final boolean logViolations;

        public RegexRule(String target, String pattern, ValidationType type) {
            this(target, pattern, type, true);
        }

        public RegexRule(String target, String pattern, ValidationType type, boolean logViolations) {
            this.target = target;
            this.pattern = Pattern.compile(pattern);
            this.type = type;
            this.logViolations = logViolations;
        }

        @Override
        public boolean validate(RequestContext requestContext, ResponseContext responseContext) {
            String content = getContent(requestContext, responseContext);
            if (content == null) {
                return true;
            }

            boolean matches = pattern.matcher(content).find();

            if (!matches && logViolations) {
                log.warn("正则验证失败: {} 不匹配模式 '{}'", getTargetDescription(), pattern.pattern());
            }

            return matches;
        }

        private String getContent(RequestContext requestContext, ResponseContext responseContext) {
            return switch (type) {
                case REQUEST_HEADER -> getHeaderValue(requestContext);
                case REQUEST_BODY -> getBodyValue(requestContext);
                case REQUEST_URL -> requestContext.getUrl();
                case RESPONSE_HEADER -> getHeaderValue(responseContext);
                case RESPONSE_BODY -> getBodyValue(responseContext);
                case RESPONSE_STATUS -> String.valueOf(responseContext.getStatusCode());
            };
        }

        private String getHeaderValue(RequestContext context) {
            Map<String, String> headers = context.getHeaders();
            return headers != null ? headers.get(target) : null;
        }

        private String getHeaderValue(ResponseContext context) {
            Map<String, String> headers = context.getHeaders();
            return headers != null ? headers.get(target) : null;
        }

        private String getBodyValue(RequestContext context) {
            Object body = context.getBody();
            return body != null ? body.toString() : null;
        }

        private String getBodyValue(ResponseContext context) {
            String body = context.getBody();
            return body != null ? body : null;
        }

        @Override
        public String getDescription() {
            return String.format("检查%s是否匹配正则表达式'%s'", getTargetDescription(), pattern.pattern());
        }

        private String getTargetDescription() {
            return switch (type) {
                case REQUEST_HEADER -> "请求头'" + target + "'";
                case REQUEST_BODY -> "请求体";
                case REQUEST_URL -> "请求URL";
                case RESPONSE_HEADER -> "响应头'" + target + "'";
                case RESPONSE_BODY -> "响应体";
                case RESPONSE_STATUS -> "响应状态码";
            };
        }

        @Override
        public String getTarget() { return target; }

        @Override
        public ValidationType getType() { return type; }
    }

    /**
     * 内容验证拦截器
     */
    private static class ContentValidationInterceptor implements RestClientInterceptor {
        private final ContentValidationConfig config;

        public ContentValidationInterceptor(ContentValidationConfig config) {
            this.config = config;
        }

        @Override
        public void preRequest(RequestContext context) {
            validateRequest(context);
        }

        @Override
        public void postResponse(ResponseContext context) {
            validateResponse(context);
        }

        @Override
        public void onError(ExceptionContext context) {
            // 可以在这里添加异常验证逻辑
        }

        private void validateRequest(RequestContext requestContext) {
            for (ValidationRule rule : config.getValidationRules()) {
                if (rule.getType() == ValidationType.REQUEST_HEADER ||
                    rule.getType() == ValidationType.REQUEST_BODY ||
                    rule.getType() == ValidationType.REQUEST_URL) {

                    if (!rule.validate(requestContext, null)) {
                        handleValidationFailure(rule, "请求验证失败");
                    }
                }
            }
        }

        private void validateResponse(ResponseContext responseContext) {
            for (ValidationRule rule : config.getValidationRules()) {
                if (rule.getType() == ValidationType.RESPONSE_HEADER ||
                    rule.getType() == ValidationType.RESPONSE_BODY ||
                    rule.getType() == ValidationType.RESPONSE_STATUS) {

                    if (!rule.validate(null, responseContext)) {
                        handleValidationFailure(rule, "响应验证失败");
                    }
                }
            }
        }

        private void handleValidationFailure(ValidationRule rule, String message) {
            String errorMessage = String.format("%s: %s", message, rule.getDescription());

            if (config.isLogViolations()) {
                log.error(errorMessage);
            }

            if (config.isFailOnViolation()) {
                throw new ContentValidationException(errorMessage);
            }
        }
    }

    /**
     * 内容验证异常
     */
    public static class ContentValidationException extends RuntimeException {
        public ContentValidationException(String message) {
            super(message);
        }

        public ContentValidationException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}